package com.bestcem.xm.user.service.impl.third;

import com.alibaba.fastjson.JSON;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.user.config.properties.GrowingioProperties;
import com.bestcem.xm.user.config.properties.SettingProperties;
import com.bestcem.xm.user.constant.CommonConstant;
import com.bestcem.xm.user.constant.SystemConstant;
import com.bestcem.xm.user.enums.OrgInnerFlagEnum;
import com.bestcem.xm.user.enums.UserInnerFlagEnum;
import com.bestcem.xm.user.grpc.client.dto.PackageDTO;
import com.bestcem.xm.user.service.dto.user.GrowingioDTO;
import com.bestcem.xm.user.service.dto.user.OrganizationDTO;
import com.bestcem.xm.user.service.dto.user.UserDTO;
import com.bestcem.xm.user.service.third.GrowingIOService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.MessageFormat;
import java.util.Optional;

/**
 * 百度营销服务类
 * API文档地址: https://dev2.baidu.com/content?sceneType=0&pageId=101211&nodeId=658&subhead=2.4%20%E8%81%94%E8%B0%83
 *
 * @author wangyunyun <yunyun.wang@idiaoyan.com>
 * @version v1.0
 * @date 2022/3/1 14:30
 */
@Slf4j
@Service
public class GrowingIOServiceImpl implements GrowingIOService {

    public static final String ERROR_MSG = "growingio上传登陆用户变量失败";

    @Autowired
    private SettingProperties settingProperties;

    @Autowired
    private GrowingioProperties growingioProperties;

    @Autowired
    private RestTemplate restTemplate;

    @Override
    public GrowingioDTO getUserProperty(UserDTO userDTO, OrganizationDTO organizationDTO, String packageName) {
        GrowingioDTO growingioDTO = new GrowingioDTO();
        // 设置公司和用户的内外部标识
        growingioDTO.setEnvironmentPpl(StringUtils.isNotBlank(settingProperties.getAppEnv())
                && SystemConstant.PROD_APP_ENV.equals(settingProperties.getAppEnv()) ? "正式环境" : "非正式环境");

        if (StringUtils.isNotBlank(settingProperties.getAppName()) && SystemConstant.XM_APP_NAME.equals(settingProperties.getAppName())) {
            growingioDTO.setIdentityPpl(UserInnerFlagEnum.getByType(
                    Optional.ofNullable(userDTO.getInnerFlag()).orElse(UserInnerFlagEnum.OUTTER.getType())
            ).getDesc());
            growingioDTO.setInternalSetPpl(OrgInnerFlagEnum.getByType(
                    Optional.ofNullable(organizationDTO.getInnerFlag()).orElse(OrgInnerFlagEnum.OUTTER.getType())
            ).getDesc());
        } else {
            growingioDTO.setIdentityPpl(UserInnerFlagEnum.OUTTER.getDesc());
            growingioDTO.setInternalSetPpl(OrgInnerFlagEnum.OUTTER.getDesc());
        }

        // 设置套餐名称
        growingioDTO.setPricingPpl(packageName);

        // userId环境隔离
        growingioDTO.setLoginUserId(userDTO.getUserId() + settingProperties.getAppEnv());

        // 租户id
        growingioDTO.setCorporationPpl(organizationDTO.getCode());

        return growingioDTO;
    }

    @Override
    public ServiceResult<String> uploadUserProperty(GrowingioDTO growingioDTO) {
        // 基线环境直接返回
        if (settingProperties.isBaseLine()) {
            return ServiceResult.success();
        }

        // 生成请求校验码
        String auth = null;
        try {
            auth = this.getUserPropertyAuthToken(growingioDTO.getLoginUserId());
        } catch (Exception e) {
            log.error("GrowingIO 请求校验码生成异常", e);
            return ServiceResult.fail("GrowingIO 请求校验码生成异常");
        }

        // 设置请求路径
        String url = MessageFormat.format(CommonConstant.UPLOAD_USER_PROPERTY_URL, growingioProperties.getProjectId(), auth);
        // 设置请求头和请求对象
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.add("Access-Token", growingioProperties.getProjectPublicKey());
        headers.add("Authorization", growingioProperties.getApiToken());
        HttpEntity<String> httpEntity = new HttpEntity<>(JSON.toJSONString(growingioDTO), headers);
        // 发送请求
        ResponseEntity<String> response = null;
        try {
            response = restTemplate.postForEntity(url, httpEntity, String.class);
        } catch (Exception e) {
            log.error(ERROR_MSG, e);
            return ServiceResult.fail(ERROR_MSG);
        }
        //设置返回值
        if (HttpStatus.OK.equals(response.getStatusCode())) {
            return ServiceResult.success();
        } else {
            log.error("growingio上传登陆用户变量失败. response = [{}]", JSON.toJSONString(response));
            return ServiceResult.fail(ERROR_MSG);
        }
    }

    @Override
    @Async
    public ServiceResult<Void> uploadGrowingio(UserDTO userDTO, OrganizationDTO organizationDTO, PackageDTO packageDTO) {
        // 获取growingio 数据对象
        GrowingioDTO userProperty = this.getUserProperty(userDTO, organizationDTO, packageDTO.getName());
        // 上传
        this.uploadUserProperty(userProperty);
        // 设置返回值
        return ServiceResult.success();
    }

    /**
     * 生成接口求校验码
     *
     * @param keyArray loginUserId用逗号拼接的字符串
     * @return String
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/5/31 11:26
     */
    private String getUserPropertyAuthToken(String keyArray) throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException {
        String message = "ai=" + growingioProperties.getProjectId() + "&loginUserId=" + keyArray;
        Mac hmac = Mac.getInstance("HmacSHA256");
        hmac.init(new SecretKeySpec(growingioProperties.getProjectSecretKey().getBytes(StandardCharsets.UTF_8.name()), "HmacSHA256"));
        byte[] signature = hmac.doFinal(message.getBytes(StandardCharsets.UTF_8.name()));
        return Hex.encodeHexString(signature);
    }

}
